﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;

namespace SentientGrid
{
    class AttributeParser
    {
        private Type _type;

        public PropertyInfo[] GetDisplayedProperties()
        {
            return (_type
                .GetProperties()
                .Where(t => (t.GetCustomAttributes(typeof(DisplayGridAttribute), false)
                    .Cast<DisplayGridAttribute>()
                    .Where(u => u.DisplayGrid == true)).Count() > 0)).ToArray();

        }

        public AttributeParser(Type mType)
        {
            _type = mType;
        }

        /// <summary>
        /// Finds the property on the type designated as the primary key
        /// </summary>
        /// <returns>PropertyInfo</returns>
        public PropertyInfo GetPrimaryKeyProperty()
        {
            return (_type
                .GetProperties()
                .Where(t => t.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0)
                .FirstOrDefault());
        }

        /// <summary>
        /// Creates a name/value dictionary pairing property names with their displayed values
        /// </summary>
        /// <returns>Dictionary</returns>
        public IDictionary<string, object> GetDisplayNameAttributeValues()
        {
            return GetAttributeValueForProperties(typeof(DisplayNameAttribute), (t, u) => (t != null ? (t as DisplayNameAttribute).DisplayName : u.Name));
        }

        public IDictionary<string, object> GetGridColumnWidthAttributeValues()
        {
            return GetAttributeValueForProperties(typeof(GridColumnWidthAttribute), (t, u) => t != null ? (t as GridColumnWidthAttribute).Width.ToString() : "''");
        }

        public IDictionary<string, object> GetGridColumnEditableAttributeValues()
        {
            return GetAttributeValueForProperties(typeof(GridColumnEditableAttribute), (t, u) => t != null ? (t as GridColumnEditableAttribute).IsEditable.ToJSValue() : "false");
        }

        public IDictionary<string, object> GetGridColumnFormatterAttributeValues()
        {
            return GetAttributeValueForProperties(typeof(GridColumnFormatterAttribute), (t, u) => 
            {
                if (t != null)
                {
                    var v = (t as GridColumnFormatterAttribute);
                    return string.Format("formatter:'{0}',formatoptions:{1}", v.Formatter, v.FormatOptions);
                }
                else
                {
                    return string.Empty;
                }
            });
        }

        public IDictionary<string, object> GetGridColumnCustomAttributeValues()
        {
            return GetAttributeValueForProperties(typeof(GridColumnCustomAttribute), (t, u) =>
            {
                var sb = new StringBuilder();
                var v = (t as GridColumnCustomAttribute);
                if (v != null)
                {
                    for (var i = 0; i < v.Names.Count(); i++)
                    {
                        sb.AppendFormat("{0}:{1},", v.Names[i], v.Values[i]);
                    }

                    if (sb.Length > 0) sb.RemoveLast();

                    
                }

                return sb.ToString();
            });
        }

        /// <summary>
        /// Returns as a set of Attribute classes of a given type for a given class
        /// </summary>
        /// <param name="type">Attribute Type we want to query for</param>
        /// <param name="func">A lamba expression for handling nulls if you wish to override the default return</param>
        /// <returns>Dictionary consisting of property name and attribute value</returns>
        private Dictionary<string, object> GetAttributeValueForProperties(Type type, Func<object, PropertyInfo, object> func)
        {
            var dictionary = new Dictionary<string, object>();
 
            foreach (var i in GetDisplayedProperties())
            {
                var attr = i.GetCustomAttributes(type, false).FirstOrDefault();
                dictionary.Add(i.Name, func.Invoke(attr, i));
            }

            return dictionary;
        }
    }
}
